package com.zff.rental.utils.specification;


import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

/**
 * @author HCY
 */
public class SpecConfig {
    /**
     * 根据字段名判断是否忽略
     */
    private Predicate<String> nameIgnore;

    /**
     * 根据值判断是否忽略
     */
    private Predicate<Object> valueIgnore = SpecConfig::isEmpty;

    /**
     * equal条件查询时，是否允许为null
     * 默认false：不允许
     * true：允许null,如果空则使用条件is null查询
     */
    private boolean equalAllowNull = false;

    /**
     * notEqual条件查询时，是否允许为null
     * 默认false：不允许
     * true：允许null,如果空则使用条件is not null查询
     */
    private boolean notEqualAllowNull = false;


    /**
     * like条件查询时，是否允许为空
     * 默认false：不允许
     * true：允许空,如果空则使用条件is null查询
     */
    private boolean likeAllowEmpty = false;

    /**
     * notLike条件查询时，是否允许为空
     * 默认false：不允许
     * true：允许空,如果空则使用条件is not null查询
     */
    private boolean notLikeAllowEmpty = false;

    private static class SpecConfigHolder {
        private static final SpecConfig INSTANCE = new SpecConfig();
    }

    public static SpecConfig getInstance() {
        return SpecConfigHolder.INSTANCE;
    }

    private SpecConfig() {
    }

    /**
     * 根据字段名判断是否忽略
     */
    public static boolean isIgnoreByName(String name) {
        if (getInstance().nameIgnore != null) {
            return getInstance().nameIgnore.test(name);
        }
        return name == null || name.length() == 0;
    }

    /**
     * 根据值判断是否忽略
     */
    public static boolean isIgnoreByValue(Object value) {
        if (getInstance().valueIgnore != null) {
            return getInstance().valueIgnore.test(value);
        }
        return false;
    }

    /**
     * 对象是否null,空,空集合,空数组
     */
    private static boolean isEmpty(Object value) {
        if (value == null) {
            return true;
        }
        if (value instanceof CharSequence) {
            return ((CharSequence) value).length() == 0;
        }
        if (value instanceof Optional) {
            return ((Optional<?>) value).isPresent() && isEmpty(((Optional<?>) value).get());
        }
        if (value instanceof Collection) {
            return ((Collection<?>) value).isEmpty();
        }
        if (value instanceof Map) {
            return ((Map<?, ?>) value).isEmpty();
        }
        if (value.getClass().isArray()) {
            return Array.getLength(value) == 0;
        }
        return false;
    }

    public SpecConfig setNameIgnore(Predicate<String> nameIgnore) {
        this.nameIgnore = nameIgnore;
        return this;
    }

    /**
     * 根据值判断是否忽略
     */
    public SpecConfig setValueIgnore(Predicate<Object> valueIgnore) {
        this.valueIgnore = valueIgnore;
        return this;
    }

    /**
     * equal条件查询时，是否允许为null
     * 默认false：不允许
     * true：允许null,如果空则使用条件is null查询
     */
    public boolean isEqualAllowNull() {
        return equalAllowNull;
    }

    public SpecConfig setEqualAllowNull(boolean equalAllowNull) {
        this.equalAllowNull = equalAllowNull;
        return this;
    }

    /**
     * notEqual条件查询时，是否允许为null
     * 默认false：不允许
     * true：允许null,如果空则使用条件is not null查询
     */
    public boolean isNotEqualAllowNull() {
        return notEqualAllowNull;
    }

    public SpecConfig setNotEqualAllowNull(boolean notEqualAllowNull) {
        this.notEqualAllowNull = notEqualAllowNull;
        return this;
    }

    /**
     * like条件查询时，是否允许为空
     * 默认false：不允许
     * true：允许空,如果空则使用条件is null查询
     */
    public boolean isLikeAllowEmpty() {
        return likeAllowEmpty;
    }

    public SpecConfig setLikeAllowEmpty(boolean likeAllowEmpty) {
        this.likeAllowEmpty = likeAllowEmpty;
        return this;
    }

    /**
     * notLike条件查询时，是否允许为空
     * 默认false：不允许
     * true：允许空,如果空则使用条件is not null查询
     */
    public boolean isNotLikeAllowEmpty() {
        return notLikeAllowEmpty;
    }

    public SpecConfig setNotLikeAllowEmpty(boolean notLikeAllowEmpty) {
        this.notLikeAllowEmpty = notLikeAllowEmpty;
        return this;
    }
}
